package com.wggd.bcreader;

import java.awt.image.BufferedImage;
import java.util.Arrays;

public class Scanline {
	private static final int THRESHOLD = 127;
	private BufferedImage image;
	private int[] rgb;
	
	public Scanline(BufferedImage image, int scanlineHeight) {
		this.image = image;
		rgb = new int[image.getWidth()];
		image.getRGB(0, scanlineHeight, image.getWidth(), 1, rgb, 0, 1);
	}
	
	@Override
	public String toString() {
		int[] blackWhiteScanlineRGB = getThresholdedRGB();
		return extractScanlineRawOutput(blackWhiteScanlineRGB);
	}
	
	public int[] getThresholdedRGB() {
		return thresholdLine(rgb, THRESHOLD);
	}
	
	private String extractScanlineRawOutput(int[] blackWhiteScanlineRGB) {
		StringBuilder rawOutputBuilder = new StringBuilder();
		
		for (int i = 0; i < blackWhiteScanlineRGB.length; ++i) {
			int packedRGB = blackWhiteScanlineRGB[i];
			int[] unpackedRGB = fromPackedRGB(packedRGB);
			
			rawOutputBuilder.append(unpackedRGB[0]);
		}
		
		return rawOutputBuilder.toString();
	}

	private int[] thresholdLine(int[] srcLine, int threshold) {
		int[] newLine = new int[srcLine.length];
		
		srcLine = toGrayscale(srcLine);
		
		for (int i = 0; i < newLine.length; ++i) {
			int packedRGB = srcLine[i];
			int[] unpackedRGB = fromPackedRGB(packedRGB);
			
			int result = unpackedRGB[0] >= threshold ? 0 : 1;
			
			Arrays.fill(unpackedRGB, result);
			newLine[i] = toPackedRGB(unpackedRGB);
		}
		
		return newLine;
	}
	
	private int[] toGrayscale(int[] srcLine) {
		int[] newLine = new int[srcLine.length];
		
		for (int i = 0; i < newLine.length; ++i) {
			int packedRGB = srcLine[i];
			int[] unpackedRGB = fromPackedRGB(packedRGB);
			
			int average = (unpackedRGB[0] + unpackedRGB[1] + unpackedRGB[2]) / 3;
			
			Arrays.fill(unpackedRGB, average);
			newLine[i] = toPackedRGB(unpackedRGB);
		}
		
		return newLine;
	}
	
	private int toPackedRGB(int[] unpackedRGB) {
		return toPackedRGB(unpackedRGB[0], unpackedRGB[1], unpackedRGB[2]);
	}
	
	private int toPackedRGB(int red, int green, int blue) {
		return (red << 16) + (green << 8) + blue;
	}
	
	private int[] fromPackedRGB(int packedRGB) {
		return new int[] {(packedRGB & 0x00FF0000) >> 16,
						  (packedRGB & 0x0000FF00) >> 8,
						  (packedRGB & 0x000000FF)};
	}
}
